Text-to-SQL Datasource Plugin
Overview
A Godspeed plugin that enables natural language to SQL conversion and multi-database query execution with built-in caching support. This plugin leverages Gemini models to convert natural language queries into SQL statements and executes them across various database types.
Features
- Natural language to SQL conversion using Google Gemini
- Multi-database support
- PostgreSQL
- MySQL
- MongoDB
- Oracle
- Automatic query caching with Redis
- Query validation
- Schema management
- Error handling and logging
- Connection pooling
- Resource cleanup
1. Install the Plugin
First, add the Text-to-SQL plugin using
godspeed plugin add @godspeedsystems/plugins-text-to-sql-as-datasource
Setup Environment
Create or update your .env
file with the following:
# Gemini API Configuration
GEMINI_API_KEY=your_gemini_api_key
# PostgreSQL Configuration
PG_USER=your_postgres_user
PG_HOST=localhost
PG_DB=your_database
PG_PASSWORD=your_password
PG_PORT=5432
# MySQL Configuration
MYSQL_HOST=localhost
MYSQL_USER=your_mysql_user
MYSQL_PASSWORD=your_password
MYSQL_DB=your_database
# MongoDB Configuration
MONGODB_URL=mongodb://localhost:27017
MONGODB_DB=your_database
# Oracle Configuration
ORACLE_USER=your_oracle_user
ORACLE_PASSWORD=your_password
ORACLE_CONNECT_STRING=localhost:1521/XEPDB1
# Redis Configuration
REDIS_URL=redis://localhost:6379
DataSource Configuration
Check your auto generated YAML configuration file src/datasources/text-to-sql.yaml
:
type: text-to-sql
config:
gemini:
apiKey: ${GEMINI_API_KEY}
databases:
postgres:
enabled: true
config:
user: ${PG_USER}
host: ${PG_HOST}
database: ${PG_DB}
password: ${PG_PASSWORD}
port: ${PG_PORT}
cache:
enabled: true
url: ${REDIS_URL}
Define the Event (API Endpoint)
Create src/events/sql-query.yaml
:
http.post./sql-query:
summary: "Convert natural language to SQL and execute"
description: "Endpoint to convert natural language to SQL query and execute it"
fn: execute-query
authn: false
body:
content:
application/json:
schema:
type: object
properties:
query:
type: string
description: "Natural language query to be converted to SQL"
dbType:
type: string
description: "Target database type (postgres, mysql, etc.)"
default: "postgres"
required:
- query
responses:
200:
description: "Successful query execution"
content:
application/json:
schema:
type: object
3. Write Event Handler Function
Create src/functions/execute-query.ts
:
import { GSContext, PlainObject } from "@godspeedsystems/core";
async function handler(ctx: GSContext): Promise<PlainObject> {
try {
const { body } = ctx.inputs.data;
if (!body.query) {
throw new Error("Query is required");
}
// Execute the query using the text-to-sql datasource
const result = await ctx.datasources['text-to-sql'].execute(ctx, {
query: body.query,
dbType: body.dbType || 'postgres',
validateOnly: false,
cache: true
});
return {
success: true,
data: result
};
} catch (error: any) {
ctx.logger.error('Query execution failed:', error);
return {
success: false,
code: 500,
message: error.message,
data: {
message: "Query execution failed"
}
};
}
}
export default handler;
Database Setup
PostgreSQL Container Setup
# Run PostgreSQL container
sudo docker run --name test-postgres \
-e POSTGRES_USER=testuser \
-e POSTGRES_PASSWORD=testpass \
-e POSTGRES_DB=testdb \
-p 5434:5432 \
-d postgres:latest
# Create test data
psql -h localhost -p 5434 -U testuser -d testdb
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100),
status VARCHAR(20)
);
INSERT INTO users (name, email, status) VALUES
('John Doe', 'john@example.com', 'active'),
('Jane Smith', 'jane@example.com', 'inactive');
Redis Cache Setup
# Run Redis container
sudo docker run --name test-redis \
-p 6380:6379 \
-d redis:latest
Test API
POST /sql-query
Request Body
{
"query": "find all active users",
"dbType": "postgres"
}
Response
{
"success": true,
"data": {
"rows": [
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"status": "active"
}
],
"metadata": {
"rowCount": 1,
"executionTime": "0.123s"
}
}
}
Key Benefits
-
Developer Productivity
- No need to write SQL queries manually
- Rapid prototyping and development
- Focus on business logic instead of query syntax
-
End User Experience
- Natural language interface to databases
- Faster query results with caching
- Reduced learning curve
-
Enterprise Ready
- Production-grade security
- Scalable architecture
- Comprehensive logging
- Performance optimization
Advanced Examples
Complex Queries
{
"query": "Show me total sales by category for active products in last quarter",
"dbType": "postgres"
}
Analytical Queries
{
"query": "Calculate monthly growth rate of user signups",
"dbType": "postgres"
}
Security Features
- Query validation before execution
- SQL injection prevention
- Rate limiting support
- Error handling and sanitization
- Secure database connections
Performance
- Redis caching reduces database load
- Query optimization suggestions
- Connection pooling
- Execution time monitoring
- Cache hit ratio tracking
Example Usage
Basic Query Event Configuration
Create a new file src/events/query.yaml
:
'http.post./query':
fn: execute-query
body:
content:
application/json:
schema:
type: object
properties:
query:
type: string
dbType:
type: string
default: postgres
required: ['query']
Query Execution Workflow
Define your function src/functions/execute-query.yaml
:
id: execute-query
summary: Execute natural language query
tasks:
- id: convert-and-execute
fn: datasource.text-to-sql.execute
args:
query: <% inputs.body.query %>
dbType: <% inputs.body.dbType || 'postgres' %>
Example Requests
- Simple Query Request:
curl -X POST http://localhost:3000/query \
-H "Content-Type: application/json" \
-d '{"query": "Find all active users"}'
- Complex Query Request:
curl -X POST http://localhost:3000/query \
-H "Content-Type: application/json" \
-d '{
"query": "Show total sales by category for the last quarter",
"dbType": "mysql"
}'
Example Responses
{
"sql": "SELECT category, SUM(amount) AS total_sales FROM sales WHERE date >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH)",
"data": [
{
"category": "Electronics",
"total_sales": 105000
}
],
"metadata": {
"rowCount": 1,
"executionTime": 48
}
}
Error Handling
{
"error": "QUERY_ERROR",
"message": "Failed to execute query",
"details": "Syntax error at or near 'total'"
}
Limitations
- Natural language processing depends on Google Gemini
- Redis required for caching functionality
- Database-specific features may vary
Troubleshooting
Common Issues
-
Connection Failures
- Verify database credentials
- Check network connectivity
- Ensure services are running
-
Query Generation Issues
- Validate Google gemini API key
- Check query format
- Review database schema
-
Cache Problems
- Verify Redis connection
- Check cache configuration
- Monitor memory usage